#pragma once

#include "/home/lhr/http-server/Log.hpp"
#include <iostream>
#include <mysql/mysql.h>
#include <vector>
#include <ctime>
#include <cstdio>
#include <cinttypes>
#include <jsoncpp/json/json.h>

// const std::string host ="localhost";
const std::string HOST = "120.46.25.211";
const std::string USER = "lhr";
const std::string PASSWD = "lhr.547521";
const std::string DB = "httpSvr_DB";
const unsigned int PORT = 3306;

enum
{
    SUCCESS,
    CONN_ERR,
    QUERY_ERR,
    GET_RESULT_ERR,
    NO_USR,
    PASSWD_ERR,
    USR_EXISTS,           // 用户名已存在
    INSERT_ERR,           // 插入数据失败
    UPDATE_ERR,           // 更新数据失败
    SESSION_TOKEN_INVALID // session_token无效
};

class DBManager
{
private:
    MYSQL *_connect;
    bool _isConnected;
    MYSQL_RES *queryResult;
    MYSQL_ROW line;
    my_ulonglong rows;
    unsigned int cols;

private:
    DBManager()
        : _connect(nullptr), _isConnected(false), queryResult(nullptr), rows(0), cols(0), line(nullptr)
    {
        LOG(INFO, "mysql client Version %s ", mysql_get_client_info());
        _connect = mysql_init(NULL);
        if (_connect == NULL)
        {
            LOG(FATAL, " %s 获取数据库句柄失败", mysql_error(_connect));
            return;
        }

        // 连接到数据库
        if (mysql_real_connect(_connect, HOST.c_str(), USER.c_str(), PASSWD.c_str(), DB.c_str(), PORT, NULL, 0) == NULL)
        {
            LOG(FATAL, " %s 数据库连接失败", mysql_error(_connect));
            mysql_close(_connect);
            return;
        }
        mysql_set_character_set(_connect, "utf8");
        LOG(INFO, "%s 数据库连接成功", DB.c_str());
        _isConnected = true;
    }

    ~DBManager()
    {
        if (_isConnected)
        {
            if (queryResult)
                mysql_free_result(queryResult); // 释放结果集

            if (_connect)
                mysql_close(_connect);
            _isConnected = false;
        }
    }
    // 禁用拷贝构造和赋值运算符
    DBManager(const DBManager &) = delete;
    DBManager &operator=(const DBManager &) = delete;

public:
    // 懒汉式单例模式 第一次使用时再创建
    static DBManager &GetInstance()
    {
        static DBManager instance;
        return instance;
    }

    // 通过用户名和密码判断：1. 用户是否存在 2. 密码是否正确
    int CheckUser(const std::string &username, const std::string &password)
    {
        if (!_isConnected)
        {
            LOG(FATAL, "数据库未连接");
            return CONN_ERR;
        }
        std::string sql = "select * from users where username='" + username + "';";
        if (mysql_query(_connect, sql.c_str()))
        {
            LOG(FATAL, " %s 查询失败", mysql_error(_connect));
            return QUERY_ERR;
        }
        queryResult = mysql_store_result(_connect);
        if (queryResult == NULL)
        {
            LOG(FATAL, " %s 获取结果集失败", mysql_error(_connect));
            return GET_RESULT_ERR;
        }
        rows = mysql_num_rows(queryResult);
        if (rows == 0)
        {
            LOG(INFO, "用户不存在");
            return NO_USR;
        }
        line = mysql_fetch_row(queryResult);
        if (line[2] != password)
        {
            LOG(FATAL, "密码错误！");
            return PASSWD_ERR;
        }
        return SUCCESS;
    }

    // 注册用户 1. 用户名是否已存在 2. 插入新用户
    int RegisterUser(const std::string &username, const std::string &password)
    {
        if (!_isConnected)
        {
            LOG(FATAL, "数据库未连接");
            return CONN_ERR;
        }

        // 检查用户名是否已存在
        std::string sqlCheck = "SELECT * FROM users WHERE username='" + username + "';";
        if (mysql_query(_connect, sqlCheck.c_str()))
        {
            LOG(FATAL, " %s 查询失败", mysql_error(_connect));
            return QUERY_ERR;
        }

        queryResult = mysql_store_result(_connect);
        if (queryResult == NULL)
        {
            LOG(FATAL, " %s 获取结果集失败", mysql_error(_connect));
            return GET_RESULT_ERR;
        }

        int rows = mysql_num_rows(queryResult);

        if (rows > 0)
        {
            LOG(INFO, "用户名已存在");
            return USR_EXISTS;
        }

        // 用户名不存在 执行插入操作
        std::string sqlInsert = "INSERT INTO users (username, password) VALUES ('" + username + "', '" + password + "');";
        if (mysql_query(_connect, sqlInsert.c_str()))
        {
            LOG(FATAL, " %s 插入用户失败", mysql_error(_connect));
            return INSERT_ERR;
        }

        LOG(INFO, "用户%s注册成功", username.c_str());
        return SUCCESS;
    }

    // 根据用户名插入会话令牌到数据库
    int InsertToken(const std::string &username, const std::string &token)
    {
        if (!_isConnected)
        {
            LOG(FATAL, "数据库未连接");
            return CONN_ERR;
        }

        // 更新会话令牌 SQL 语句
        std::string sqlUpdate = "UPDATE users SET session_token='" + token + "' WHERE username='" + username + "';";
        if (mysql_query(_connect, sqlUpdate.c_str()))
        {
            LOG(FATAL, " %s 插入令牌失败", mysql_error(_connect));
            return INSERT_ERR;
        }

        LOG(INFO, "用户%s的会话令牌已更新为%s", username.c_str(), token.c_str());
        return SUCCESS;
    }

    // 检查用户表中是否存在该session_token
    int CheckSessionToken(const std::string &session_token)
    {
        if (!_isConnected)
        {
            LOG(FATAL, "数据库未连接");
            return CONN_ERR;
        }

        std::string sql = "SELECT user_id FROM users WHERE session_token='" + session_token + "'";

        if (mysql_query(_connect, sql.c_str()))
        {
            LOG(FATAL, "数据库查询失败: %s", mysql_error(_connect));
            return QUERY_ERR;
        }

        // 获取查询结果
        queryResult = mysql_store_result(_connect);
        if (queryResult == nullptr)
        {
            LOG(FATAL, "获取查询结果失败: %s", mysql_error(_connect));
            return GET_RESULT_ERR;
        }

        // 检查是否有返回记录(session_token是否存在)
        rows = mysql_num_rows(queryResult);
        if (rows < 0)
            return SESSION_TOKEN_INVALID;

        return SUCCESS;
    }

    // 根据session_token获取用户ID
    int GetUserIdByToken(const std::string &session_token, int &user_id)
    {
        if (!_isConnected)
        {
            LOG(FATAL, "数据库未连接");
            return CONN_ERR;
        }

        std::string sql = "SELECT user_id FROM users WHERE session_token='" + session_token + "'";

        if (mysql_query(_connect, sql.c_str()))
        {
            LOG(FATAL, "数据库查询失败: %s", mysql_error(_connect));
            return QUERY_ERR;
        }

        // 获取查询结果
        queryResult = mysql_store_result(_connect);
        if (queryResult == nullptr)
        {
            LOG(FATAL, "获取查询结果失败: %s", mysql_error(_connect));
            return GET_RESULT_ERR;
        }

        // 检查是否有返回记录(session_token是否有效)
        rows = mysql_num_rows(queryResult);
        if (rows < 0)
            return SESSION_TOKEN_INVALID;

        MYSQL_ROW row = mysql_fetch_row(queryResult);
        user_id = std::stoi(row[0]);
        return SUCCESS;
    }

    // 更新用户最后一次登录时间
    int UpdateLastLoginTime(const std::string &username)
    {
        if (!_isConnected)
        {
            LOG(FATAL, "数据库未连接");
            return CONN_ERR;
        }

        std::string sql = "UPDATE users SET last_login=NOW() WHERE username='" + username + "'";

        if (mysql_query(_connect, sql.c_str()))
        {
            LOG(FATAL, "更新用户最后一次登录时间失败: %s", mysql_error(_connect));
            return UPDATE_ERR;
        }
        return SUCCESS;
    }

    // 添加文章
    int addArticle(const std::string &title, const std::string &content, int author_id)
    {
        if (!_isConnected)
        {
            LOG(FATAL, "数据库未连接");
            return CONN_ERR;
        }

        // 构建插入文章的SQL语句
        std::string sql = "INSERT INTO articles (title, content, author_id) VALUES ('" +
                          title + "', '" + content + "', " + std::to_string(author_id) + ");";

        // 执行SQL语句
        if (mysql_query(_connect, sql.c_str()))
        {
            LOG(FATAL, "插入文章失败: %s", mysql_error(_connect));
            return INSERT_ERR;
        }

        LOG(INFO, "文章标题为'%s'的文章发布成功", title.c_str());
        return SUCCESS;
    }

    // 根据文章标题查找文章(可能存在同名文章)
    std::vector<Json::Value> searchArticle(const std::string &title)
    {
        std::vector<Json::Value> articles;

        if (!_isConnected)
        {
            LOG(FATAL, "数据库未连接");
            return articles; // 返回空的Json对象
        }

        // 根据标题查询文章
        std::string sql = "SELECT articles.article_id, articles.title, articles.content, users.username AS author, articles.publish_date"
                          " FROM articles JOIN users ON articles.author_id = users.user_id"
                          " WHERE articles.title = '" +
                          title + "';";
        if (mysql_query(_connect, sql.c_str()))
        {
            LOG(FATAL, "查询失败: %s", mysql_error(_connect));
            return articles;
        }

        queryResult = mysql_store_result(_connect);
        if (queryResult == NULL)
        {
            LOG(FATAL, "获取结果集失败: %s", mysql_error(_connect));
            return articles;
        }

        rows = mysql_num_rows(queryResult);
        if (rows == 0)
        {
            LOG(INFO, "没有找到标题为'%s'的文章", title.c_str());
            return articles; // 返回空的Json对象
        }

        while ((line = mysql_fetch_row(queryResult)))
        {
            Json::Value article;
            article["id"] = std::stoi(line[0]); // 文章ID
            article["title"] = line[1];         // 标题
            article["content"] = line[2];       // 内容
            article["author"] = line[3];        // 作者ID
            article["date"] = line[4];          // 发布时间

            articles.push_back(article); // 将文章添加到列表中
        }

        return articles;
    }

    // 获取所有文章
    std::vector<Json::Value> getAllArticles()
    {
        std::vector<Json::Value> articles;

        if (!_isConnected)
        {
            LOG(FATAL, "数据库未连接");
            return articles;
        }

        // 查询所有文章
        std::string sql = "SELECT articles.article_id, articles.title, articles.content, users.username AS author, articles.publish_date"
                          " FROM articles JOIN users ON articles.author_id = users.user_id;";
        if (mysql_query(_connect, sql.c_str()))
        {
            LOG(FATAL, "查询失败: %s", mysql_error(_connect));
            return articles;
        }

        queryResult = mysql_store_result(_connect);
        if (queryResult == NULL)
        {
            LOG(FATAL, "获取结果集失败: %s", mysql_error(_connect));
            return articles;
        }

        rows = mysql_num_rows(queryResult);
        while ((line = mysql_fetch_row(queryResult)))
        {
            Json::Value article;
            article["id"] = std::stoi(line[0]); // 文章ID
            article["title"] = line[1];         // 标题
            article["content"] = line[2];       // 内容
            article["author"] = line[3];        // 作者ID
            article["date"] = line[4];          // 发布时间
            articles.push_back(article);        // 将文章添加到列表中
        }

        return articles;
    }

    // 根据文章ID获取文章信息
    Json::Value getArticleById(const std::string &articleId)
    {
        Json::Value article;

        std::string sql = "SELECT a.article_id, a.title, a.content, u.username AS author, a.publish_date "
                          "FROM articles a "
                          "JOIN users u ON a.author_id = u.user_id "
                          "WHERE a.article_id = '" +
                          articleId + "';";
        if (mysql_query(_connect, sql.c_str()))
        {
            LOG(FATAL, "查询失败: %s", mysql_error(_connect));
            return article; // 查询失败，返回空的Json对象
        }

        queryResult = mysql_store_result(_connect);
        if (queryResult == NULL)
        {
            LOG(FATAL, "获取结果集失败: %s", mysql_error(_connect));
            return article; // 获取结果集失败，返回空的Json对象
        }

        line = mysql_fetch_row(queryResult);
        if (line != NULL)
        {
            article["id"] = std::stoi(line[0]); // 文章ID
            article["title"] = line[1];         // 标题
            article["content"] = line[2];       // 内容
            article["author"] = line[3];        // 作者名
            article["date"] = line[4];          // 发布时间
        }

        return article;
    }

    // 根据文章ID获取评论信息
    Json::Value getCommentsForArticle(const std::string &articleId)
    {
        Json::Value comments(Json::arrayValue);

        std::string sql = "SELECT c.content, u.username AS commenter, c.comment_date "
                          "FROM comments c "
                          "JOIN users u ON c.commenter_id = u.user_id "
                          "WHERE c.article_id = '" +
                          articleId + "';";
        if (mysql_query(_connect, sql.c_str()))
        {
            LOG(FATAL, "查询失败: %s", mysql_error(_connect));
            return comments; // 查询失败，返回空的Json数组
        }

        queryResult = mysql_store_result(_connect);
        if (queryResult == NULL)
        {
            LOG(FATAL, "获取结果集失败: %s", mysql_error(_connect));
            return comments; // 获取结果集失败，返回空的Json数组
        }

        MYSQL_ROW line;
        while ((line = mysql_fetch_row(queryResult)))
        {
            Json::Value comment;
            comment["content"] = line[0];   // 评论内容
            comment["commenter"] = line[1]; // 评论者
            comment["date"] = line[2];      // 评论时间
            comments.append(comment);       // 将评论添加到数组中
        }

        return comments;
    }

    // 添加评论
    int addComment(int articleId, int userId, const std::string &content)
    {
        if (!_isConnected)
        {
            LOG(FATAL, "数据库未连接");
            return CONN_ERR;
        }

        // 构建插入评论的 SQL 语句
        std::string sql = "INSERT INTO comments (article_id, content, commenter_id) VALUES (" +
                          std::to_string(articleId) + ", '" + content + "', " + std::to_string(userId) + ");";
        // 执行 SQL 语句
        if (mysql_query(_connect, sql.c_str()))
        {
            LOG(FATAL, "插入评论失败: %s", mysql_error(_connect));
            return INSERT_ERR;
        }

        LOG(INFO, "文章ID为'%d'的评论发布成功", articleId);
        return SUCCESS;
    }
};
